/*
 * A simple ToDo Manager
 *
 * Copyright (c) 2011 Nosheen Zaza, Manuel Rebollo, Seyedsaeid Mahpeikar and
 * Wo Ke
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package todomanager.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Observable;
import java.util.Observer;
import java.util.prefs.Preferences;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.ImageIcon;

import todomanager.model.Task;
import todomanager.model.TaskManager;

import todomanager.ui.dialogs.NewTaskDialog;
import todomanager.ui.dialogs.HowToUseDialog;
import todomanager.ui.dialogs.AboutDialog;
import todomanager.ui.dialogs.TasksTodayDialog;

import todomanager.ui.tableview.TaskCellEditor;
import todomanager.ui.tableview.TaskDisplayTable;
import todomanager.ui.tableview.TaskTableModel;
import todomanager.ui.listview.TaskListModel;

/**
 * The main window of the application, serves as the main part of the view.
 * 
 * @author
 * Nosheen Zaza
 * @author
 * Seyedsaeid Mahpeikar
 * @author
 * Manuel Rebollo
 * @author
 * Wo Ke
 */
public class MainWindow extends JFrame implements Observer {

    private ToDoMenuBar menuBar;
    private JButton newTaskButton;
    private TaskDisplayTable taskTable;
    private JScrollPane taskScroll;
    private JPanel newTaskButtonPanel;
    private JPanel frameContentsPanel;
    private JPanel mainFrameContentPanel;
    private Background background;
    private NewTaskDialog addTaskDialog;
    private AboutDialog aboutDialog;
    private HowToUseDialog howToUseDialog;
    private TasksTodayDialog tasksTodayDialog;
    private Clock currentTime;
    private Preferences settings, currentUserRoot;
    private ClassLoader loader;
    private static final int INITIAL_WIDTH = 500;
    private static final int INITIAL_HEIGHT = 350;

    /*
     * Initialize the main window and its components.
     */
    public MainWindow() {

        newTaskButton = new JButton();
        newTaskButton.setAction(ActionControl.getInstance().getNewTaskAction());
        newTaskButton.setContentAreaFilled(false);
        newTaskButton.setBorderPainted(false);
        newTaskButton.setBorder(null);
        newTaskButton.setText("");

        loader = this.getClass().getClassLoader();

        /* Initialize the button panel. */
        newTaskButtonPanel = new ImagePanel(new ImageIcon(
                loader.getResource(
                    "todomanager/resources/NewTaskButton_"
                    +ActionControl.getInstance().getCurrentLocale().getLanguage()
                    +".png")).getImage());
        newTaskButtonPanel.setLayout(new BorderLayout());
        newTaskButtonPanel.add(newTaskButton);
        newTaskButtonPanel.setOpaque(false);

        /* Initialize the task display area. */
        taskTable = new TaskDisplayTable(
                new TaskTableModel(TaskManager.getInstance().getTaskList()));
        taskScroll = new JScrollPane(taskTable);
        taskScroll.setHorizontalScrollBarPolicy(
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        taskScroll.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        taskScroll.setOpaque(false);
        taskScroll.getViewport().setOpaque(false);

        frameContentsPanel = new JPanel();
        frameContentsPanel.setLayout(new BoxLayout(
                frameContentsPanel, BoxLayout.PAGE_AXIS));
        frameContentsPanel.setOpaque(false);


        frameContentsPanel.add(taskScroll);

        mainFrameContentPanel = new JPanel();
        mainFrameContentPanel.setLayout(new BorderLayout());
        mainFrameContentPanel.add(frameContentsPanel, BorderLayout.CENTER);
        mainFrameContentPanel.setOpaque(false);

        /* To show the current time */
        ImagePanel currentTimePanel = new ImagePanel(new ImageIcon(
                loader.getResource(
                "todomanager/resources/CurrentTime.png")).getImage());
        currentTimePanel.setLayout(new BorderLayout());
        currentTime = new Clock();
        currentTime.run();
        currentTimePanel.add(BorderLayout.WEST, currentTime);

        /*
         * Initialize the dialog boxes.
         */
        addTaskDialog = new NewTaskDialog();
        aboutDialog = new AboutDialog();
        howToUseDialog = new HowToUseDialog();

        background = new Background();
        background.getCenterBackgroundPanel().setLayout(new BorderLayout());
        background.getCenterBackgroundPanel().add(mainFrameContentPanel, BorderLayout.NORTH);
        
        /* Initialize the menu bar. */
        menuBar = new ToDoMenuBar();
        menuBar.setOpaque(true);
        menuBar.setUI(null);

        /*
         * Add the menu bar to the main window.
         * It is not the default place, but looks normal.
         */
        background = new Background();
        background.getForMenuMiddlePanel().add(menuBar, BorderLayout.CENTER);
        background.getInnerFrameTopPanel().add(currentTimePanel, BorderLayout.EAST);
        background.getInnerFrameTopPanel().add(newTaskButtonPanel, BorderLayout.BEFORE_LINE_BEGINS);

        /*
         * Add the components of the main window on the top of the background 
         * image.
         */
        background.getCenterBackgroundPanel().setLayout(new BorderLayout());
        background.getCenterBackgroundPanel().add(mainFrameContentPanel, BorderLayout.CENTER);

        /*
         * Add the graphical background and the main window components to 
         * the frame.
         */
        getContentPane().add(background, BorderLayout.CENTER);

        // Load size from registry.
        currentUserRoot = Preferences.userRoot();
        settings = currentUserRoot.node("Group6.ToDoManager.preference.size");
        int width = Integer.valueOf(settings.get(
                "Width", String.valueOf(INITIAL_WIDTH)));
        int height = Integer.valueOf(settings.get(
                "Height", String.valueOf(INITIAL_HEIGHT)));
        setSize(width, height);
        setMinimumSize(new Dimension(INITIAL_WIDTH, INITIAL_HEIGHT));

        // Load location from registry.
        settings = currentUserRoot.node("Group6.ToDoManager.preference.location");
        setLocation(Integer.valueOf(settings.get(
                "X", "100")), Integer.valueOf(settings.get("Y", "100")));

        setTitle(ActionControl.getInstance().getStringsBundle().getString("title"));

        /*
         * When closing the main window, we will actually save changes to
         * edited and deleted tasks.
         */
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                MainWindow.this.closeApplication();
            }
        });
    }

    /**
     * Updates the view according to model changes.
     * @param o
     * @param arg
     */
    public void update(Observable o, Object arg) {
        if (arg instanceof ArrayList) {
            ArrayList<Task> taskList = (ArrayList<Task>) arg;
            /*
             * After the initial data load, set the model of the table,
             * and prepare today's tasks dialog.
             */
            taskTable.setModel(new TaskTableModel(taskList));
            tasksTodayDialog = new TasksTodayDialog();


        } else if (arg instanceof Task || arg == null) {
            TaskListModel listModel =
                    (TaskListModel) tasksTodayDialog.getTaskDisplayList().getModel();
            listModel.updateModel(TaskManager.getInstance().getTaskList());
            taskTable.revalidate();
            taskTable.repaint();
        }
    }

    /**
     * Does some house keeping tasks and closes the application.
     */
    public void closeApplication() {
        // Find if there is some task being edited, and save the edit changes.
        if (taskTable.getEditingRow() != -1
                && taskTable.getEditingColumn() != -1) {
            TaskCellEditor tce = (TaskCellEditor) taskTable.getCellEditor(
                    taskTable.getEditingRow(), taskTable.getEditingColumn());
            Task t = (Task) tce.getCellEditorValue();
            if (t != null) {
                TaskManager.getInstance().editTaskText(t, t.getText());
                TaskManager.getInstance().editTaskPriority(t, t.getPriority());
                TaskManager.getInstance().editTaskCategory(t, t.getCategory());
                TaskManager.getInstance().editTaskProgress(t, t.getProgress());
                TaskManager.getInstance().editTaskStatus(t, t.isDone());

                if(t.getDueDate() != null)
                    TaskManager.getInstance().editTaskDate(t,
                            t.getDueDate().get(GregorianCalendar.YEAR),
                            t.getDueDate().get(GregorianCalendar.MONTH),
                            t.getDueDate().get(GregorianCalendar.DATE));
            }
        }

        // Save the current state of the application to the system registery.
        TaskManager.getInstance().saveSession();
        // Save size in registry.
        settings = currentUserRoot.node("Group6.ToDoManager.preference.size");
        settings.put("Width", String.valueOf(Math.round(getSize().getWidth())));
        settings.put("Height", String.valueOf(Math.round(getSize().getHeight())));
        // Save location in registry
        settings = currentUserRoot.node("Group6.ToDoManager.preference.location");
        settings.put("X", String.valueOf(Math.round(getLocation().getX())));
        settings.put("Y", String.valueOf(Math.round(getLocation().getY())));
        System.exit(0);
    }

    /**
     * Returns the add task dialog box.
     * @return addTaskDialog
     */
    public NewTaskDialog getAddTaskDialog() {
        return addTaskDialog;
    }

    /**
     * Gets the about dialog instance.
     * @return aboutDialog
     */
    public AboutDialog getAboutDialog() {
        return aboutDialog;
    }

    /**
     * Gets the how to use dialog instance.
     * @return howToUseDialog
     */
    public HowToUseDialog getHowToUseDialog() {
        return howToUseDialog;
    }

    /**
     * Returns today's tasks dialog
     * @return tasksToday
     */
    public TasksTodayDialog getTasksTodayDialog() {
        return tasksTodayDialog;
    }

    /**
     * Returns the task display table
     * @return taskTable
     */
    public TaskDisplayTable getTaskTable() {
        return taskTable;
    }
}
